#include "SRTF_Scheduler.h"
#include <iostream>
#include <vector>

using namespace std;

SRTF_Scheduler::SRTF_Scheduler()
{
}

void SRTF_Scheduler::sortProcesses()
{
	vector<Process>::iterator end, positionOne, positionTwo;
	bool swapped = true;

	end = processList.end();

	do
	{
		swapped = false;
		positionTwo = ++processList.begin();
		for(positionOne = processList.begin(); positionTwo != end; positionOne++, positionTwo++)
		{
			if(compareArrivalTime(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SRTF_Scheduler::compareArrivalTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getArrivalTIme() > (*positionTwo).getArrivalTIme();
}
/*
void SRTF_Scheduler::runScheduler()
{
	vector<Process>::iterator index, end, tempProcessListItr;
	vector<Process> ready_queue, tempProcessList;
	int endTime = 0, arrivalTime, arrival_difference;
	Process temp(0,0,0);

	//needed to ensure there wont be a problem with resource allocation of the vector
	//during run-time. 
	ready_queue.reserve(700);
	sortProcesses();

	tempProcessList = processList;

	tempProcessListItr = tempProcessList.begin();

	index = tempProcessList.begin();

	

	do
	{
		if(index != tempProcessList.end())
		{
			int size = tempProcessList.size();
			ready_queue.push_back(tempProcessList.front());
			arrivalTime = (ready_queue.front()).getArrivalTIme();
			tempProcessList.erase(tempProcessListItr);

			for(tempProcessListItr = tempProcessList.begin(); tempProcessListItr != tempProcessList.end() && (*tempProcessListItr).getArrivalTIme() == arrivalTime; )
			{
				ready_queue.push_back(*tempProcessListItr);
				tempProcessList.erase(tempProcessListItr);
				tempProcessListItr = tempProcessList.begin();
			}

			index = tempProcessList.begin();

			//first process executed
			if(endTime == 0)
				(*index).setStartTime((*index).getArrivalTIme());
			else
				(*index).setEndTime(endTime);
		
			//when the process can finish if continued un-interrupted
			endTime = (*index).getStartTime() + (*index).getCPU_Burst();
			arrival_difference = (ready_queue.front()).getArrivalTIme() - (*index).getArrivalTIme();

			while((index + 1) != tempProcessList.end() && !needSwitched(index, arrival_difference) && (*index).getArrivalTIme() < endTime)
			{
				index++;
				arrival_difference = (ready_queue.front()).getArrivalTIme() - (*index).getArrivalTIme();
			}

			
			

			if(index != tempProcessList.end())
			{
				//no candidiates were found that the current executing process can be switched with before the current
				//process finishes execution
				if((*index).getArrivalTIme() >= endTime)
				{
					(ready_queue.front()).setStartTime((ready_queue.front()).getArrivalTIme());
					(ready_queue.front()).setEndTime((ready_queue.front()).getStartTime() + (ready_queue.front()).getCPU_Burst());
					endTime = (ready_queue.front()).getEndTime();
					assignValuesToProcessList(ready_queue.front());
				}
				else
				{ //process will be switched out
					if((ready_queue.front()).getArrivalTIme() > endTime)
						(ready_queue.front()).setStartTime((ready_queue.front()).getArrivalTIme());
					else
						(ready_queue.front()).setStartTime(endTime);

					arrival_difference = (ready_queue.front()).getArrivalTIme() - (*index).getArrivalTIme();
						
					(ready_queue.front()).setCPU_Burst((ready_queue.front()).getCPU_Burst() - arrival_difference);
					(ready_queue.front()).setEndTime((ready_queue.front()).getStartTime() + arrival_difference);
					ready_queue.push_back(ready_queue.front());
					ready_queue.erase(ready_queue.begin());
				}
				ready_queue.insert(ready_queue.begin(), *index);
			}		

			index = tempProcessList.begin();

			tempProcessListItr = tempProcessList.begin();
		}

	}while(tempProcessList.size() != 0);

	for(vector<Process>::iterator begin = processList.begin(); begin != processList.end(); begin++)
		cout << (*begin).getArrivalTIme() << "     " << (*begin).getCPU_Burst() << endl;

}*/

bool SRTF_Scheduler::needSwitched(vector<Process>::iterator index, int arrival_difference)
{
	return (arrival_difference - (*index).getCPU_Burst() < 0) && (*(index + 1)).getCPU_Burst() < (*index).getCPU_Burst() - arrival_difference;
}


void SRTF_Scheduler::sortByBurstTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo, vector<Process> &queue)
{
	vector<Process>::iterator end, posOne, posTwo;
	bool swapped;

	posOne = positionOne;
	posTwo = (posOne + 1);

	do
	{
		cout << "ive been called ..... finally!\n";
		swapped = false;
		for(posOne = positionOne; posTwo != positionTwo; posOne++, posTwo++)
		{
			if(compareBurstTime(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SRTF_Scheduler::compareBurstTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getCPU_Burst() > (*positionTwo).getCPU_Burst();
}

void SRTF_Scheduler::assignValuesToProcessList(Process temp)
{
	vector<Process>::iterator location;
	location = processList.begin();
	findProcessID(location, temp.getProcessID());

	(*location).setEndTime(temp.getEndTime());
	(*location).setStartTime(temp.getStartTime());
	(*location).setFinished();

}

void SRTF_Scheduler::findProcessID(vector<Process>::iterator &location, int processID)
{
	while((*location).getProcessID() != processID)
		location++;
}


void SRTF_Scheduler::runScheduler()
{
	vector<Process>::iterator index, end, tempProcessListItr, ready_queueItr;
	vector<Process> ready_queue, tempProcessList;
	int endTime = 0, arrivalTime, arrival_difference;
	Process temp(0,0,0);

	//needed to ensure there wont be a problem with resource allocation of the vector
	//during run-time. 
	ready_queue.reserve(1000);
	sortProcesses();

	tempProcessList = processList;

	ready_queue.push_back(tempProcessList.front());
	tempProcessList.erase(tempProcessList.begin());
	index = tempProcessList.begin();

	do
	{

		arrival_difference = (ready_queue.front()).getArrivalTIme() - (*index).getArrivalTIme();

		//find a candidate for switching
		while((index + 1) != tempProcessList.end() && !needSwitched(index, arrival_difference) && (*index).getArrivalTIme() < endTime)
		{
			index++;
		}

		//no candidate for switching was found, so the process will finish its run
		if((index + 1) == tempProcessList.end() || (*index).getArrivalTIme() > endTime)
		{
			(*(ready_queue.begin())).setStartTime((*(ready_queue.begin())).getArrivalTIme());
			(*(ready_queue.begin())).setEndTime((*(ready_queue.begin())).getArrivalTIme() + (*(ready_queue.begin())).getCPU_Burst());
			endTime = (*(ready_queue.begin())).getEndTime();
			assignValuesToProcessList(ready_queue.front());
			ready_queue.erase(ready_queue.begin());
		}
		else
		{ //candidate was found for context switch

			if(!(*(ready_queue.begin())).wasProcessed())
			{
				(*(ready_queue.begin())).setStartTime(endTime);
			}
			else
				(*(ready_queue.begin())).setProcessed();

			
			(*(ready_queue.begin())).setEndTime(endTime + arrival_difference);
			(*(ready_queue.begin())).setCPU_Burst((*(ready_queue.begin())).getCPU_Burst() - arrival_difference);
			endTime = (*(ready_queue.begin())).getEndTime();
			ready_queue.push_back(ready_queue.front());
			ready_queue.erase(ready_queue.begin());
			ready_queue.insert((ready_queue.begin()), *index);
		}

		ready_queue.push_back(tempProcessList.front());
		tempProcessList.erase(tempProcessList.begin());
		index = tempProcessList.begin();


	}while(ready_queue.size() != 0);

	for(vector<Process>::iterator begin = processList.begin(); begin != processList.end(); begin++)
		cout << (*begin).getArrivalTIme() << "     " << (*begin).getCPU_Burst() << endl;
}
		


